package com.jsftoolkit.gen.info;

/**
 * Describes a property of a component, including whether it is required or not
 * and the default value.
 * 
 * @author noah
 * 
 */
public class PropertyInfo {
	private Class<?> type;

	private String name;

	private String defaultValue;

	private boolean required;

	private boolean defaultSaved;

	public PropertyInfo() {
		this(null, null, null);
	}

	/**
	 * Creates a {@link String} property with the given name.
	 * 
	 * @param name
	 */
	public PropertyInfo(final String name) {
		this(String.class, name);
	}

	/**
	 * Creates a property that defaults to null
	 * 
	 * @param _class
	 * @param name
	 */
	public PropertyInfo(final Class<?> _class, final String name) {
		this(_class, name, null);
	}

	/**
	 * Same as {@link #PropertyInfo(Class, String, String, boolean)}, but with
	 * required set to false.
	 * 
	 * @param _class
	 * @param name
	 * @param defaultValue
	 */
	public PropertyInfo(final Class<?> _class, final String name,
			final String defaultValue) {
		this(_class, name, defaultValue, false);
	}

	/**
	 * this(_class, name, defaultValue, required, false);
	 */
	public PropertyInfo(final Class<?> _class, final String name,
			final String defaultValue, final boolean required) {
		this(_class, name, defaultValue, required, false);
	}

	/**
	 * 
	 * @param _class
	 *            the class of the property (leave null for properties that
	 *            should only pass through a constant and be specified in the
	 *            tag handler, such as VALUE)
	 * @param name
	 *            the name of the property.
	 * @param defaultValue
	 *            the java code string to initialize this value. e.g. for the
	 *            int 3, "3". For the string 'foo' "\"Foo\"". For some arbitrary
	 *            object: "new MyClass(foo,bar,baz)";
	 * @param required
	 *            id this property required?
	 * @param defaultSaved
	 *            should the default value be saved to the field when returned?
	 */
	public PropertyInfo(Class<?> type, String name, String defaultValue,
			boolean required, boolean defaultSaved) {
		super();
		this.type = type;
		this.name = name;
		this.defaultValue = defaultValue;
		this.required = required;
		this.defaultSaved = defaultSaved;
	}

	/**
	 * 
	 * @return the class of the property
	 */
	public Class<?> getType() {
		return type;
	}

	/**
	 * 
	 * @return the name of the property
	 */
	public String getName() {
		return name;
	}

	/**
	 * 
	 * @return the code to generate the default value. e.g. to set it to a 3
	 *         call setDefaultValue("3"). For the string foo:
	 *         setDefaultValue("\"foo\"")
	 */
	public String getDefaultValue() {
		return defaultValue;
	}

	/**
	 * 
	 * @return true if the attribute is required
	 */
	public boolean isRequired() {
		return required;
	}

	public void setType(Class<?> _class) {
		this.type = _class;
	}

	public void setDefaultValue(String defaultValue) {
		this.defaultValue = defaultValue;
	}

	public void setName(String name) {
		this.name = name;
	}

	public void setRequired(boolean required) {
		this.required = required;
	}

	/**
	 * 
	 * @return true if the default value should be saved once returned. If
	 *         false, the default value will be recreated every time.
	 */
	public boolean isDefaultSaved() {
		return defaultSaved;
	}

	public void setDefaultSaved(boolean defaultSaved) {
		this.defaultSaved = defaultSaved;
	}

	@Override
	public int hashCode() {
		final int PRIME = 31;
		int result = 1;
		result = PRIME * result + ((name == null) ? 0 : name.hashCode());
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null) {
			return false;
		}
		if (getClass() != obj.getClass()) {
			return false;
		}
		final PropertyInfo other = (PropertyInfo) obj;
		if (name == null) {
			if (other.name != null) {
				return false;
			}
		} else if (!name.equals(other.name)) {
			return false;
		}
		return true;
	}

	/**
	 * 
	 * @return the code to regenerate this {@link PropertyInfo} instance
	 */
	public CharSequence getCodeString() {
		return String.format("new %s(%s,\"%s\",%s)",
				getClass().getSimpleName(), type == null ? null : type
						.getSimpleName()
						+ ".class", name, defaultValue);
	}

}
